package cloud.gateway.mygateway;

import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 * @auther xfanonymous
 * @create 2023-12-31 11:11
 *
 * Gateway - Predicate 断言
 *
 * 自定义断言，配置文件中指定自定义断言参数：
 * predicates:
 *   - name: My
 *   args:
 *    userType: diamond
 *
 * http://localhost:9527/pay/gateway/get/1?userType=diamond 才能通过
 * http://localhost:9527/pay/gateway/get/1?userType=silver 无法通过
 *
 * 1. 自定义类要以 xxxRoutePredicateFactory 结尾
 * 2. 继承 AbstractRoutePredicateFactory<> 类，<>中填写xxxRoutePredicateFactory.Config
 * 3. @Component
 * 4. 可以参考自带的断言API：AfterRoutePredicateFactory、BeforeRoutePredicateFactory....
 * 5. 空参构造方法，内部调用super
 * 6. 添加Config类，指定断言规则
 * 7. 重写apply方法，完成断言实现
 * 8. 在yml配置类中配置自定义断言，以 -xx 自定义断言类的前缀作为配置参数顶层
 * 9. 重写shortcutFieldOrder方法，否则yml配置文件无法进行Shortcut Configuration方式配置
 */
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{

    public MyRoutePredicateFactory() {
        super(MyRoutePredicateFactory.Config.class);
    }

    // 定义配置文件中的参数，断言规则
    @Validated
    public static class Config {
        // 会员等级
        @Setter
        @Getter
        @NotEmpty
        private String userType;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("userType");
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
    {
        return new Predicate<ServerWebExchange>()
        {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                //检查request的参数里面，userType是否为指定的值，符合配置就通过
                //http://localhost:9527/pay/gateway/get/1?userType=diamond
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
                if (userType == null) {
                    // 参数不存在就无法访问
                    return false;
                }
                // 参数存在，就和config配置文件yml中的数据进行比较
                if(userType.equalsIgnoreCase(config.getUserType())){
                    return true;
                }
                return false;
            }
        };
    }
}